#pragma once
#include <QString>
#include <set>
#include <vector>

#include "../core.h"
#include "./BaseString.h"
#include "./WideString.h"
#include "simple_array.h"

namespace qb {
namespace base {

struct S_CORE_EXPORT strinfo {
  int pos, len;

 public:
  bool operator==(const strinfo& si) { return pos == si.pos && len == si.len; }
};
//==============================================================================
// Summary:
//     reverse find c in str from ipos to 0 and return first match pos
//==============================================================================

int strrfind(const char* str, int ipos, char c);

class S_CORE_EXPORT StringUtil {
 public:
  static int SplitString(const char* str, int size, const BaseString& key,
                         std::vector<BaseString>& strings);
  static int SplitStringInfo(const char* str, int size, const BaseString& key,
                             strinfo* strings, int capcity);
  static int SplitStringInfo(const char* buffer, int size,
                             const BaseString& key,
                             std::vector<strinfo>& lines);
  static int SplitStringInfo(const char* str, int size, const BaseString& key,
                             SimpleArray<strinfo>& strings);
  static int SplitStringInfo(const wchar_t* str, int size,
                             const WideString& key, strinfo* strings,
                             int capcity);
  static int SplitStringInfoEx(const char* str, int size, const BaseString& key,
                               std::vector<strinfo>& tokens,
                               bool ignoreZeroLength = true);
  static void SplitFileNameEx(const BaseString& full, BaseString& path,
                              BaseString& base, BaseString& ext);
  static void SplitFileName(const BaseString& full, BaseString& path,
                            BaseString& name);
  static int FindInSet(const char* str, int len, BaseString strset);
  static char* LoadFileContent(const wchar_t* fileName, int& fileSize);
  static int LoadLinesFromFile(const wchar_t* fileName,
                               std::vector<BaseString>& lines,
                               const BaseString& key = "\r\n",
                               bool skipBlankLines = true);
  static const char* GetShortFileName(const char* fileName, int count);
  template <class Container>
  static bool WriteLinesImpl(const Container& lines, const BaseString& fileName,
                             bool append);
  static bool WriteLines(const std::set<BaseString>& lines,
                         const BaseString& fileName, bool append = false);
  static bool WriteLines(const std::vector<BaseString>& lines,
                         const BaseString& fileName, bool append = false);
  static bool WriteLines(const SimpleArray<BaseString>& lines,
                         const BaseString& fileName, bool append = false);
  static bool IsNumber(const char* str, int len);
  static bool IsNumber(const BaseString& str);
  static void tohex(unsigned char c, char str[]);
  static int tohex(wchar_t c, char* str);
  static QString GenerateGuidString();
  static bool SaveFileContent(const char* buf, int size,
                              const wchar_t* fileName);
  static int GetStringRealBytes(const std::string& str);
  static int GetStringAllBytes(const std::string& str);
  static void StringCopy(char* dest, int capcity, const char* source);
  static char* _strstr_cn(const char* str, char* data);
};
template <class ITEM>
void UniqueVector(std::vector<ITEM>& vec) {
  std::set<ITEM> items;
  for (auto it = vec.begin(); it != vec.end(); ++it) {
    items.insert(*it);
  }
  vec.clear();
  for (auto sit = items.begin(); sit != items.end(); ++sit) {
    vec.push_back(*sit);
  }
}

template <typename... Args>
std::string string_format(const std::string& format, Args... args) {
  const int MAX_BUF = 256;
  size_t capcity =
      1 + snprintf(nullptr, 0, format.c_str(), args...);  // Extra space for \0
  if (capcity < MAX_BUF) {
    char buf[MAX_BUF] = {0};
    snprintf(buf, capcity, format.c_str(), args...);
    return std::string(buf);
  } else {
    char* buf = new char[capcity];
    memset(buf, 0, capcity);
    snprintf(buf, capcity, format.c_str(), args...);
    std::string tmp = std::string(buf);
    delete[] buf;
    return tmp;
  }
}
}  // namespace base
}  // namespace qb
